iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
Mobile Development

Android Studio 30天進階學習系列 第 15

Android Studio 30天進階學習-DAY15_JetpackCompose的EditText輸入(TextField的詳細說明與簡易實作)

  • 分享至 

  • xImage
  •  

今天要來講Compose中的EditText功能元件

在Compose中也有EditText的輸入框元件,詳細請往下看其程式碼及呈現的效果。

TextField元件

TextField 元件就是在Compose中的EditText,今天就來說明如何使用以及當中有哪些實用的小功能。

  • TextField的撰寫格式如下:
TextField(
    //... 可以使用的參數如下
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    enabled: Boolean = true,
    readOnly: Boolean = false,
    textStyle: TextStyle = LocalTextStyle.current,
    label: @Composable (() -> Unit)? = null,
    placeholder: @Composable (() -> Unit)? = null,
    leadingIcon: @Composable (() -> Unit)? = null,
    trailingIcon: @Composable (() -> Unit)? = null,
    supportingText: @Composable (() -> Unit)? = null,
    isError: Boolean = false,
    visualTransformation: VisualTransformation = VisualTransformation.None,
    keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
    keyboardActions: KeyboardActions = KeyboardActions.Default,
    singleLine: Boolean = false,
    maxLines: Int = Int.MAX_VALUE,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    shape: Shape = TextFieldDefaults.filledShape,
    colors: TextFieldColors = TextFieldDefaults.textFieldColors()
)
  • 這邊講幾個可能比較常使用的參數好了:

    • value:就是輸入的文字
    • onValueChange:就是當數值有變換時會呼叫這個裡面的回調函數
    • modifier:就是我們前面所說過的一些外觀布局會用到的參數
    • enable:是有關這個輸入框是否能夠讓使用者輸入的參數,false就是無法輸入。
    • readOnly:如字面上的意思"唯讀",若為true就是無法修改當中的文字
    • placeholder: 當文字欄位獲得焦點且輸入文字為空時,顯示的可選佔位符。 預設情況下,佔位符的預設文字樣式為 Typography.bodyLarge。
    • leadingIcon: 可選制的前導圖示,會顯示在輸入框的最前頭的位置。
    • trailingIcon: 可選制的尾部圖示,會顯示在輸入框的最尾部位置。
    • visualTransformation: 用於轉換輸入值的視覺表示的可選轉換。 例如,您可以使用 PasswordVisualTransformation 建立一個密碼文字欄位。 預設情況下,不套用任何視覺轉換。
    • supportingText:可選的支援文本,顯示在文字欄位下方。
    • singleLine - 當設定為 true 時,此文字欄位將變為單行橫向滾動的文字字段,而不是換行到多行。 鍵盤將被告知不顯示換行鍵作為 IME 操作。 如果設定 singleLine 為 true,則 maxLines 參數將被忽略,因為最大行數屬性將自動設為 1。
    • maxLines - 以最大可見行數表示的最大高度。 應該等於或大於 1。 如果將 singleLine 設為 true,則將忽略此參數,實際上最大行數將設為 1。
    • shape - 定義此文字欄位容器的形狀。
  • 範例撰寫如下:

TextField(
    value = name,
    onValueChange = {
        name = it
    },
    leadingIcon = {
        Icon(
            painter = painterResource(id = R.drawable.ic_launcher_edit_foreground),
            contentDescription = null,
            modifier = Modifier.width(40.dp)
        )
    },
    colors = TextFieldDefaults.textFieldColors(
        focusedIndicatorColor = MaterialTheme.colorScheme.surface,
        unfocusedIndicatorColor = MaterialTheme.colorScheme.surface
    ),
    placeholder = {
        Text(stringResource(id = R.string.enter_message))
    },
    visualTransformation = PasswordVisualTransformation(),
    modifier = Modifier
        .padding(16.dp)
        .fillMaxWidth()
)

實作模擬登入主頁面

@Composable
fun enterMessage(
    context: Context
){

    var message by remember{ mutableStateOf("")}
    var name by remember{ mutableStateOf("")}

    Box(Modifier.fillMaxSize()){
        Column(modifier = Modifier.align(Alignment.Center)) {
            // 帳號輸入
            TextField(
                value = message,
                onValueChange = {
                    message = it
                },
                leadingIcon = {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_launcher_edit_foreground),
                        contentDescription = null,
                        modifier = Modifier.width(40.dp)
                    )
                },
                colors = TextFieldDefaults.textFieldColors(
                    focusedIndicatorColor = MaterialTheme.colorScheme.surface,
                    unfocusedIndicatorColor = MaterialTheme.colorScheme.surface
                ),
                placeholder = {
                    Text(stringResource(id = R.string.enter_name))
                },
                modifier = Modifier
                    .padding(16.dp)
                    .fillMaxWidth()
            )
            // 密碼輸入
            TextField(
                value = name,
                onValueChange = {
                    name = it
                },
                leadingIcon = {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_launcher_edit_foreground),
                        contentDescription = null,
                        modifier = Modifier.width(40.dp)
                    )
                },
                colors = TextFieldDefaults.textFieldColors(
                    focusedIndicatorColor = MaterialTheme.colorScheme.surface,
                    unfocusedIndicatorColor = MaterialTheme.colorScheme.surface
                ),
                placeholder = {
                    Text(stringResource(id = R.string.enter_message))
                },
                visualTransformation = PasswordVisualTransformation(),
                modifier = Modifier
                    .padding(16.dp)
                    .fillMaxWidth()
            )
            // 建立按鈕送出輸入的帳號密碼資料,以及清除輸入內容
            Row(
                Modifier
                    .fillMaxWidth(),
                horizontalArrangement = Arrangement.SpaceAround
            ) {
                // 送出
                ElevatedButton(onClick = {
                    if (message.isNotEmpty()) {
                        Log.e("Send", "enterMessage: "+message+"\nName"+name )
                        showLog(context, message = message, name = name )
                        message = ""
                        name = ""
                    }else{
                        Toast.makeText(context, "尚未輸入訊息", Toast.LENGTH_SHORT).show()
                    }
                }, modifier = Modifier
                    .weight(1f)
                    .padding(16.dp)) {
                    Text("送出")
                }
                // 清空
                ElevatedButton(onClick = {
                    if (message.isNotEmpty()) {
                        message = ""
                        name = ""
                    }else{
                        Toast.makeText(context, "請輸入訊息", Toast.LENGTH_SHORT).show()
                    }
                }, modifier = Modifier
                    .weight(1f)
                    .padding(16.dp)) {
                    Text("清除")
                }
            }
        }
    }
}

// 點擊送出訊息後傳入並回傳Toast
fun showLog(
    context: Context,
    message: String,
    name: String
){
    Toast.makeText(
        context,
        "Message: $message\nName: $name",
        Toast.LENGTH_SHORT
    ).show()
}

// 組合背景圖案
@Composable
fun getImage(
    context: MainActivity
) {
    val image = painterResource(id = R.drawable.ic_launcher_abd_foreground)
    Box(modifier = Modifier.fillMaxSize()) {
        Image(
            painter = image,
            contentDescription = null,
            contentScale = ContentScale.Crop,
            modifier = Modifier.fillMaxSize()
        )
        Icon(painterResource(
            id = R.drawable.baseline_attractions_24),
            contentDescription = null,
            modifier = Modifier.padding(32.dp).align(Alignment.TopCenter))
        enterMessage(context)
    }
}

// 預覽圖程式碼
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    JetpackCompose_KotlinTheme {
        getImage(context = MainActivity())
    }
}
  • 預覽圖
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370g4BZarzIgb.png
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370voHSWsTNkH.png

主程式碼_執行部分

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            JetpackCompose_KotlinTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
//                    Greeting("Android")
                    getImage(context = this)
                }
            }
        }
    }
}

如何建立自製圖案

這邊我是在drawable中建立圖案來使用,現在就來說明如何建立內建的圖示並使用吧。

首先到如下的位置drawable按下滑鼠右鍵後指到Image Asset後點擊
https://ithelp.ithome.com.tw/upload/images/20230925/20150370BI27SwS8LU.png
點擊後會跳出以下的畫面
https://ithelp.ithome.com.tw/upload/images/20230925/20150370AHbJmdpQQs.png

  • 這邊命名的部分不要與現有的圖示名稱重複就好
  • 然後點擊Clip art的圖示會跳出以下畫面
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370DW9jeeesQt.png
  • 在上面這個Icon中選擇自己需要的圖示
  • 看個人需求更改顏色
  • 完成後點擊Next進到下一個步驟
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370b8N95GtFkD.png
    接著按下Finish就完成一個Icon圖示的建立了。
  • 注意:這邊雖然有一個功能是可以直接呼叫Icons.Default."需要的圖片名稱"可以取得Icon,但我這邊不知道為何無法正常取得,所以就使用了土法煉鋼的方式置入Icon

執行的結果截圖

  • 直向輸入截圖
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370iN8iouF4dd.jpg

  • 直向送出截圖
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370VpRPQBRY1l.jpg

  • 橫向輸入
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370RpehAodUQW.jpg

  • 橫向送出
    https://ithelp.ithome.com.tw/upload/images/20230925/20150370bgeMADJDtm.jpg

總結

今天所作的說明是在Compose中建立TextField,也就是如同EditText一般的輸入文字的元件。

在這邊我使用了前置的Icon去作標示,這邊我覺得這個功能十分方便,以往想要在XML建立一個登入主頁面並放入Icon來標示帳號密碼,需要再建立一個ImageView並依附在EditText旁邊才有類似的效果。


上一篇
Android Studio 30天進階學習-DAY14_JetpackCompose的三大版面元素(Column、Row、Box)說明以及Button的樣式及簡易點擊功能
下一篇
Android Studio 30天進階學習-DAY15_JetpackCompose的底部導航欄(NavigationBar&NavigationBarItem的詳細說明實作)
系列文
Android Studio 30天進階學習30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言